package cn.ciis.sys.login;

import cn.ciis.basic.kit.J2CacheKit;
import cn.ciis.basic.model.Account;
import cn.ciis.basic.model.Session;
import cn.ciis.sys.permission.PermissionAdminService;
import cn.ciis.sys.role.RoleAdminService;
import com.jfinal.aop.Inject;
import com.jfinal.kit.HashKit;
import com.jfinal.kit.Ret;
import com.jfinal.kit.StrKit;
import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.Record;
import net.oschina.j2cache.CacheObject;

import java.util.Calendar;
import java.util.Date;

/**
 * 登录业务
 */
public class LoginService {

    @Inject
    RoleAdminService roleAdminService;

    @Inject
    PermissionAdminService permissionAdminService;

    private Account accountDao = new Account().dao();

    // 存放登录用户的 cacheName
    public static final String LOGIN_ACCOUNT_CACHE_NAME = "loginAccount";

    public static final String SESSION_ID_NAME = "CiisAId";

    /**
     * 登录成功返回 sessionId 与 loginAccount，否则返回一个 msg
     */
    public Ret login(String userName, String password,boolean keepLogin, String loginIp) {
        userName = userName.toLowerCase().trim();
        password = password.trim();
        Account loginAccount = accountDao.findFirst("select * from sys_account where userName=? limit 1",userName);
        if (loginAccount == null) {
            return Ret.fail("msg", "用户名或密码不正确");
        }
        if (loginAccount.isStatusLockId()) {
            return Ret.fail("msg", "账号已被锁定");
        }
        if (loginAccount.isStatusReg()) {
            return Ret.fail("msg", "账号未激活，请先激活账号");
        }
        Integer id1 = loginAccount.getId();
        String salt = loginAccount.getSalt();
        String hashedPass = HashKit.sha256(salt + password);
        // 未通过密码验证
        if (loginAccount.getPassword().equals(hashedPass) == false) {
            return Ret.fail("msg", "用户名或密码不正确");
        }
        // 否则为 120 分钟，单位为秒
        long liveSeconds = keepLogin ? 3 * 365 * 24 * 60 * 60 : 120 * 60;
        // 传递给控制层的 cookie
        int maxAgeInSeconds = (int)(keepLogin ? liveSeconds : -1);
        // expireAt 用于设置 session 的过期时间点，需要转换成毫秒
        long expireAt = System.currentTimeMillis() + (liveSeconds * 1000);
        // 保存登录 session 到数据库
        Session session = new Session();
        String sessionId = StrKit.getRandomUUID();
        session.setId(sessionId);
        session.setAccountId(loginAccount.getId());
        session.setExpireAt(expireAt);
        session.setTimestamp(Calendar.getInstance().getTimeInMillis() / 1000);
        Record record = Db.findFirst("SELECT * FROM `sys_session` WHERE accountId = ?", id1);
        if (record != null) {
            //删除登录用户session
            J2CacheKit.evict(LOGIN_ACCOUNT_CACHE_NAME,record.getStr("id"));
            Db.delete("delete from sys_session where accountId=?", record.get("accountId").toString());
        }
        if (!session.save()) {
            return Ret.fail("msg", "保存 session 到数据库失败，请联系管理员");
        }
        // 移除 password 与 salt 属性值
        loginAccount.removeSensitiveInfo();
        // 保存一份 sessionId 到 loginAccount 备用
        loginAccount.put("sessionId", sessionId);

        loginAccount.put("roles", roleAdminService.findMyRoles(loginAccount.getId()));//查询当前登录人角色
        loginAccount.put("pers", permissionAdminService.findMyPermission(loginAccount));//查询当前登录人拥有的权限

        J2CacheKit.set(LOGIN_ACCOUNT_CACHE_NAME, sessionId,loginAccount);

        createLoginLog(loginAccount.getId(), loginIp);

        return Ret.ok(SESSION_ID_NAME, sessionId)
                .set(LOGIN_ACCOUNT_CACHE_NAME, loginAccount)
                // 用于设置 cookie 的最大存活时间
                .set("maxAgeInSeconds", maxAgeInSeconds);
    }

    public Account getLoginAccountWithSessionId(String sessionId) {

        CacheObject cacheObject = J2CacheKit.get(LOGIN_ACCOUNT_CACHE_NAME, sessionId, key -> {
            Session session = Session.DAO.findById(sessionId);
            // session 不存在
            if (session == null) {
                return null;
            }
            // session 已过期
            if (session.isExpired()) {
                // 被动式删除过期数据，此外还需要定时线程来主动清除过期数据
                session.delete();
                return null;
            }
            Account loginAccount = accountDao.findById(session.getAccountId());
            if (loginAccount != null && loginAccount.isStatusOk()) {
                // 移除 password 与 salt 属性值
                loginAccount.removeSensitiveInfo();
                // 保存一份 sessionId 到 loginAccount 备用
                loginAccount.put("sessionId", sessionId);
                loginAccount.put("roles", roleAdminService.findMyRoles(loginAccount.getId()));//查询当前登录人角色
                loginAccount.put("pers", permissionAdminService.findMyPermission(loginAccount));//查询当前登录人拥有的权限
                J2CacheKit.set(LOGIN_ACCOUNT_CACHE_NAME, sessionId, loginAccount);
                return loginAccount;
            } else {
                return false;
            }
        });

        if(cacheObject != null && cacheObject.getValue() !=null){
            return (Account) cacheObject.getValue();
        }else{
            return null;
        }

    }

    /**
     * 通过 sessionId 获取登录用户信息 sessoin表结构：session(id, accountId, expireAt)
     *
     * <p>1：先从缓存里面取，如果取到则返回该值，如果没取到则从数据库里面取 2：在数据库里面取，如果取到了，则检测是否已过期，如果过期则清除记录， 如果没过期则先放缓存一份，然后再返回
     */
    public Account loginWithSessionId(String sessionId, String loginIp) {
        Session session = Session.DAO.findById(sessionId);
        // session 不存在
        if (session == null) {
            return null;
        }
        // session 已过期
        if (session.isExpired()) {
            // 被动式删除过期数据，此外还需要定时线程来主动清除过期数据
            session.delete();
            return null;
        }

        Account loginAccount = accountDao.findById(session.getAccountId());
        // 找到 loginAccount 并且 是正常状态 才允许登录
        if (loginAccount != null && loginAccount.isStatusOk()) {
            // 移除 password 与 salt 属性值
            loginAccount.removeSensitiveInfo();
            // 保存一份 sessionId 到 loginAccount 备用
            loginAccount.put("sessionId", sessionId);
            loginAccount.put("roles", roleAdminService.findMyRoles(loginAccount.getId()));//查询当前登录人角色
            loginAccount.put("pers", permissionAdminService.findMyPermission(loginAccount));//查询当前登录人拥有的权限
            J2CacheKit.set(LOGIN_ACCOUNT_CACHE_NAME,sessionId,loginAccount);
            createLoginLog(loginAccount.getId(), loginIp);
            return loginAccount;
        }
        return null;
    }

    /**
     * 创建登录日志
     */
    private void createLoginLog(Integer accountId, String loginIp) {
        Record loginLog =
                new Record().set("accountId", accountId).set("ip", loginIp).set("loginAt", new Date());
        Db.save("sys_login_log", loginLog);
    }


    /**
     * 退出登录
     */
    public void logout(String sessionId) {
        if (sessionId != null) {
            J2CacheKit.evict(LOGIN_ACCOUNT_CACHE_NAME,sessionId);
            Session.DAO.deleteById(sessionId);
        }
    }
}
